#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // fork
#include <sys/types.h>
#include <sys/ipc.h> // ftok
#include <sys/msg.h> // 消息队列
#include <errno.h>
#include <sys/random.h>
#include <signal.h> // kill
#include <sys/wait.h> // waitpid
extern int errno;
typedef struct {
	long mtype; // 消息类型，必须放在第一个
	unsigned int index;
	char msg[10];
} msgbuf;
pid_t g_child_pid;

void random_init()
{
	srand(0);
}

char random_char()
{
	return 0x20 + rand() % (0x7e - 0x20 + 1);
}

void random_string(char *str, unsigned int len)
{
	for (unsigned int i = 0; i < len; ++i) {
		str[i] = random_char();
	}
}

void kill_child_process(pid_t pid)
{
	kill(pid, SIGKILL);
	waitpid(pid, NULL, 0);
	printf("child process %d terminated\n", pid);
}

void parent_process_interrupted_callback(int signum)
{
	kill_child_process(g_child_pid);
	printf("parent process %d is going to be terminated\n", getpid());
	exit(0);
}

int parent(key_t key, pid_t child_pid)
{
	int ret;
	int queue;
	int status;
	msgbuf buf;
	memset(&buf, 0, sizeof(msgbuf));

	g_child_pid = child_pid;
	signal(SIGINT, parent_process_interrupted_callback); // 拦截Ctri-C传递过来的信号

	ret = msgget(key, IPC_CREAT | 0666);
	if (ret == -1) {
		printf("get msg queue failed.%s\n", strerror(errno));
		return ret;
	}
	queue = ret;
	while (1) {
		buf.mtype = 10;
		buf.index++;
		random_string(buf.msg, 10);
		ret = msgsnd(queue, &buf, sizeof(buf), IPC_NOWAIT);
		if (ret == -1) {
			printf("send msg error.%s\n", strerror(errno));
		} else {
			printf("[%d]send msg:%s\n", buf.index, buf.msg);
		}
		sleep(2);
	}
	msgctl(queue, IPC_RMID, NULL);
	kill_child_process(child_pid);
	return 0;
}

int child(key_t key)
{	
	int ret;
	int queue;
	msgbuf buf;
	ret = msgget(key, IPC_CREAT | 0666);
	if (ret == -1) {
		printf("get msg queue failed.%s\n", strerror(errno));
		return ret;
	}
	queue = ret;
	while (1) {
		ret = msgrcv(queue, &buf, sizeof(buf), 0, 0);
		if (ret == -1) {
			printf("recv msg error.%s\n", strerror(errno));
		} else {
			printf("[%d]recv msg:%s\n", buf.index, buf.msg);
		}
	}
	msgctl(queue, IPC_RMID, NULL);
	return 0;
}

int main(int argc, char *argv[])
{
	int ret = 0;
	int status;
	key_t key = ftok("/usr/lib", 666);
	if (key == -1) {
		printf("ftok generate failed.%s\n", strerror(errno));
		return -1;
	}

	random_init();
	
	pid_t c = fork();
	if (c) { // 返回值是子进程pid，代表父进程
		ret = parent(key, c);
	} else { // 返回值是0，代表子进程
		ret = child(key);
	}

	return ret;
}